package com.shi.aspect;

import cn.hutool.json.JSONUtil;
import com.shi.annotation.cache.MyCacheEvict;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashSet;
import java.util.Set;

@Aspect
@Component
public class CacheEvictAspect {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Pointcut("@annotation(com.shi.annotation.cache.MyCacheEvict)")
    public void pointCut() {
    }

    @Before("pointCut()")
    public void handle(JoinPoint joinPoint) {
        Set<String> set = parseSpEl(joinPoint);
        Set<String> allKeys = new HashSet<>();
        for (String n : set) {
            Set<String> keys = stringRedisTemplate.keys(n);
            if (keys != null && !keys.isEmpty()) {
                allKeys.addAll(keys);
            }
        }
        stringRedisTemplate.delete(allKeys);
    }

    /**
     * 解析注解 @MyCacheEvict中属性keys的SpEl
     *
     * @param joinPoint
     * @return
     */
    private Set<String> parseSpEl(JoinPoint joinPoint) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        MyCacheEvict annotation = method.getAnnotation(MyCacheEvict.class);
        Object[] args = joinPoint.getArgs();
        Parameter[] parameters = method.getParameters();
        // 向SpEL上下文注入参数信息
        for (int i = 0; i < parameters.length; i++) {
            context.setVariable(parameters[i].getName(), args[i]);
        }
        // 使用解析器，在上下文中解析目标表达式
        Set<String> set = new HashSet<>();
        for (String key : annotation.likeKeys()) {
            set.add(JSONUtil.toJsonStr(parser.parseExpression(key).getValue(context)));
        }
        return set;
    }
}
